#include "QRONode_P.h"

struct tempObjectData{
    ObjectID id;
    QList<ObjectID> registerList;
    QString className;
    //    QString identity;
};

typedef QHash<ObjectID,tempObjectData> ObjDataMap;

static ObjDataMap parseObjPacket(QRONode::Private* _P,QVariant value);
static void createAndRegister(QRONode::Private* _P,ObjDataMap map,QList<QObject*>& linked);
static void registerRecursive(QRONode::Private* _P,QObject* target,QList<ObjectID>& regList);
static void observerDestruction(QRONode::Private* _P,ObjectData* target);
static void linkObject(QRONode::Private* _P,ObjectData* target,const QList<ObjectID>& remoteRegisterList,QList<QObject*> & linked);
static void unregisterObjectImp(QRONode::Private*_P,QObject *obj,ObjectID id);


void QRONode::Private::handleObjPacket(QVariant value,QList<QObject*>& created)
{
    auto dataMap = parseObjPacket(this,value);
    createAndRegister(this,dataMap,created);
}

void QRONode::Private::onNewObject(QByteArray data)
{
    auto var = uncompressVariant(data);
    QList<QObject*> linked;
    handleObjPacket(var,linked);
}

void QRONode::Private::onUnregisterObject(QObject* obj)
{
    auto urlist = obj->findChildren<QObject*>(Qt::FindChildrenRecursively);
    urlist.prepend(obj);
    for(auto i:urlist)
    {
        auto id = m_objectIdMap.value(i,NullID);
        if(id)
        {
            unregisterObjectImp(this,i,id);
        }
    }

    for(auto i:urlist)
    {
        emit _Q->objectDislinked(i);
    }
}

void QRONode::Private::onHostObjectRemoved(QList<quint32> list)
{
    for(auto i:list)
    {
        auto localId = m_remoteIdMapper.value(i,NullID);

        if(!localId) continue;
        auto data = m_objectDataMap[localId];
        auto obj = data->obj;
        onUnregisterObject(data->obj);

        //注销对象并进行通知后将对象进行析构
        obj->deleteLater();
    }
}

static ObjDataMap parseObjPacket(QRONode::Private* _P,QVariant value){
    ObjDataMap dataMap;

    QVariantList varList = value.toList();
    //解析报文内容
    for(auto i:varList)
    {
        auto map = i.toMap();

        tempObjectData d;
        d.id = map["id"].value<ObjectID>();
        d.registerList = map["reglist"].value<QList<ObjectID>>();
        d.className = map["className"].toString();
        //        d.identity = map["idName"].toString();
        dataMap[d.id] = d;
    }

    return dataMap;
}

//根据报文信息创建并链接对象
static void createAndRegister(QRONode::Private* _P,ObjDataMap map,QList<QObject*>& linked){
    for(const auto & i:map)
    {
        //只有注册列表非空的节点才能被创建
        if(!i.registerList.empty())
        {
            auto meta = QRemoteObject2Meta::Instance()->fetchRemoteClass(i.className);
            if(meta)
            {
                auto target = meta->constructor();
                QList<ObjectID> registerList;
                registerRecursive(_P,target,registerList);
                auto objectData = _P->m_objectDataMap[registerList[0]];
                objectData->registerList = registerList;
                linkObject(_P,objectData.get(),i.registerList,linked);
            }
        }
    }
}

//将远端对象和本地对象进行链接
static void linkObject(QRONode::Private* _P,ObjectData* target,const QList<ObjectID>& remoteRegisterList,QList<QObject*> & linked){

    if(remoteRegisterList.size() != target->registerList.size())
    {
        return;
    }

    for(auto i = 0;i<target->registerList.size();i++)
    {
        auto localId = target->registerList[i];
        auto remoteId = remoteRegisterList[i];

        auto localData = _P->m_objectDataMap.value(localId);
        if(!localData) return;
        linked << localData->obj;
        _P->m_remoteIdMapper[remoteId] = localId;
    }
}

//递归的注册对象
static void registerRecursive(QRONode::Private* _P,QObject* target,QList<ObjectID>& regList){
    if(QRemoteObject2Meta::Instance()->isRegistered(target->metaObject()->className()))
    {
        auto id = _P->allocObjectID();
        auto data = std::make_shared<ObjectData>();
        data->id = id;
        data->obj = target;
        _P->m_objectDataMap[id] =data;
        _P->m_objectIdMap[target] = id;
        target->setProperty("__RO_Net_Obj",QVariant::fromValue(_P->_Q));//注册时留下联系方式
        observerDestruction(_P,data.get());
        regList << id;
    }
    for(auto i:target->children())
    {
        registerRecursive(_P,i,regList);
    }
}

static void observerDestruction(QRONode::Private* _P,ObjectData* target){
    auto obj = target->obj;
    target->connections << QObject::connect(obj,&QObject::destroyed,[=](){
        _P->_Q->unregisterObject(obj);
    });

}

static void unregisterObjectImp(QRONode::Private*_P,QObject *obj,ObjectID id){
    auto data = _P->m_objectDataMap[id];

    for(auto i:data->connections)
    {
        QObject::disconnect(i);
    }

    _P->m_objectIdMap.remove(obj);
    _P->m_objectDataMap.remove(id);
    _P->m_remoteIdMapper.remove(_P->m_remoteIdMapper.key(id));
}
